<template>
  <form
    class="z-form"
    role="form"
    @submit.prevent="onSubmit"
    autocomplete="off"
  >
    <slot
      :cBinds="componentBinds"
      :errors="errors"
      :values="values"
      :resetForm="resetForm"
    ></slot>
  </form>
</template>
<script setup lang="ts">
import {
  useForm,
  type SubmissionContext,
  type FormContext,
} from "vee-validate";
import { toTypedSchema } from "@vee-validate/zod";
import { type ZodSchema, z } from "zod";

interface Props {
  initialValues: Record<string, any>;
  rules?: ZodSchema;
}

const props = withDefaults(defineProps<Props>(), {
  rules: () => z.object({}),
});
// 定义表单事件：success 表单验证成功，failure 表单验证失败
const emit = defineEmits<{
  success: [values: any, ctx: SubmissionContext];
  failure: [Partial<Record<string, string>>];
}>();

const {
  values,
  errors,
  defineComponentBinds,
  handleSubmit,
  resetForm,
  setValues,
  setFieldValue,
  setErrors,
  setFieldError,
} = useForm({
  initialValues: props.initialValues,
  validationSchema: toTypedSchema(props.rules),
});

// 提供将来需要绑定的字段组件
const componentBinds = reactive<
  Record<string, ReturnType<FormContext["defineComponentBinds"]>>
>(
  Object.fromEntries(
    Object.keys(props.initialValues).map((v) => [
      v,
      defineComponentBinds(v, { validateOnModelUpdate: true }),
    ]),
  ),
);
// 提供HTML元素绑定
// const inputBinds = Object.fromEntries(
//   Object.keys(props.initialValues).map((v) => [
//     v,
//     defineInputBinds(v, { validateOnInput: true }),
//   ]),
// );
// 表单验证
const onSubmit = handleSubmit(
  (values, ctx) => {
    emit("success", values, ctx);
  },
  ({ errors }) => {
    emit("failure", errors);
  },
);

defineExpose({
  values,
  errors,
  resetForm,
  setValues,
  setFieldValue,
  setErrors,
  setFieldError,
  submit: onSubmit,
});
</script>
